package psn.qiuyiping.autocad.dxffile;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Map;

public class DxfBlockReader implements DxfProcessFunc<Object> {
    public static Map<Integer, Member> redo(Class<?> cls) {
        Map<Integer, Member> funcs = new java.util.TreeMap<>();

        for (Field field : cls.getDeclaredFields()) {
            DxfCode f = field.getAnnotation(DxfCode.class);
            if (f == null) {
                continue;
            }
            funcs.put(f.value(), field);
        }

        for (Method method : cls.getDeclaredMethods()) {
            DxfCode f = method.getAnnotation(DxfCode.class);
            if (f == null) {
                continue;
            }
            funcs.put(f.value(), method);
        }
        return funcs;
    }

    protected Map<Integer, Member> fields;

    public DxfBlockReader() {
        super();
        fields = initFields();
    }

    public void afterBlockEnd(DxfProcessContext context) {
    }

    public void beforeBlockStart(DxfProcessContext context) {
    }

    public void empty(DxfProcessContext context, DxfData<Object> item) {
    }

    public Map<Integer, Member> initFields(){
        return new java.util.TreeMap<>(redo(this.getClass()));
    }

    public void readDxf(DxfProcessContext context, DxfData<Object> item) {
        if (readDxfBody0(context, item)) {
            readDxfBody(context, item);
        }
    }

    public void readDxfBody(DxfProcessContext context, DxfData<Object> item) {
        Member member = fields.get(item.code);
        if (member != null) {
            try {
                if (member instanceof Field) {
                    ((Field) member).set(this, item.getVal());
                } else {
                    ((Method) member).invoke(this, context, item);
                }
            } catch (IllegalArgumentException | IllegalAccessException
                    | InvocationTargetException e) {
                e.printStackTrace();
            }
        } else {
            unhandleCode(context, item);
        }
    }

    public boolean readDxfBody0(DxfProcessContext context, DxfData<Object> item) {
        return false;
    }

    public void unhandleCode(DxfProcessContext context, DxfData<Object> item) {
        System.out.print("\tclass " +this.getClass().getSimpleName());
        System.out.println(" - code " +item.code);
        try {
            Method m =  DxfBlockReader.class.getDeclaredMethod("empty", DxfProcessContext.class, DxfData.class);
            fields.put(item.getCode(), m);
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
